﻿import java.io.*;

public class Edl {
	static final int MAXMOD=5,MAXOBJ=1000;
	static final int FATALE=0,NONFATALE=1;
	static Descripteur[] tabDesc = new Descripteur[MAXMOD+1];
	static int ipo,nMod,nbErr;
	static String nomProg;
	private static String[][] dicoDef = new String[3][60];
	private static int[][] adFinale = new int[6][10];
	private static int[] transDon = new int[6];
	private static int[] transCode = new int[6];
	private static int tailleGlobaux;
	private static int tailleCode;
	private static int placeDico = 0, placeTrans = 0;
	private static int transExt[][] = new int[100][2];
	private static String nomModule[] = new String[MAXMOD+1]; 

	static void erreur(int te,String m) {
		System.out.println(m);
		if (te == FATALE) {
			System.out.println("ABANDON DE L'EDITION DE LIENS");;
			System.exit(1);
		}
		nbErr=nbErr+1;
	}

	static void lireDescripteurs() {
		boolean existe=false;
		String s;
		System.out.println("les noms doivent etre fournis sans suffixe");
		System.out.print("nom du programme : ");
		s=Lecture.lireString();
		nomProg=s;
		tabDesc[0]=new Descripteur();
		tabDesc[0].lireDesc(s);
		if (!tabDesc[0].unite.equals("programme")) 
			erreur(FATALE,"programme attendu");

		while (!s.equals("RC") && nMod<MAXMOD) {
			System.out.print("nom de module "+(nMod+1)+" (RC si termine) ");
			s=Lecture.lireString();
			if (!s.equals("RC")) {
				nMod=nMod+1;
				nomModule[nMod] = s;
				tabDesc[nMod]=new Descripteur();
				tabDesc[nMod].lireDesc(s);
				if (!tabDesc[nMod].unite.equals("module"))
					erreur(FATALE,"module attendu");
			}
		}
	}

	static void constMap() {

		OutputStream f1=Ecriture.ouvrir(nomProg+".map");
		if (f1==null) erreur(FATALE,"creation du fichier "+
				nomProg+".map impossible");

		InputStream f= Lecture.ouvrir(nomProg+".obj");
		if (f==null) {
			System.out.println("impossible de lire "+nomProg+".obj");
			System.exit(1);
		}

		int[] po = new int[(nMod+1)*MAXOBJ+1];

		/**
		 * Lecture du fichier pour le programme 
		 */
		for(int u = 0 ; u < tabDesc[0].nbTransExt*2 ; u++){
			if(u%2 == 0){
				transExt[placeTrans][0] = Lecture.lireInt(f);
				//System.out.print(transExt[placeTrans][0] + " ");
			}
			else{
				transExt[placeTrans][1] = Lecture.lireInt(f);
				//System.out.println(transExt[placeTrans][1]);
				placeTrans++;
			}
		}

		for(int i = 1 ; i <= tabDesc[0].tailleCode ; i++){
			po[i] = Lecture.lireInt(f);
			//System.out.println(po[i]);
			ipo++;
		}

		/**
		 * Modification avec transExt
		 */
		po[2] = tailleGlobaux;
		for(int i = 0; i < tabDesc[0].nbTransExt; i++){
			po[transExt[i][0]] = adFinale[0][po[transExt[i][0]]-1];
		}
		Lecture.fermer(f);

		/**
		 * lecture des modules 
		 */
		for(int i = 1 ; i <= nMod ; i++){
			System.out.println("Module " + i);
			InputStream f2 = Lecture.ouvrir(nomModule[i]+".obj");
			if (f==null) {
				System.out.println("impossible de lire " + nomModule[i] + ".obj");
				System.exit(1);
			}
			transExt = new int[100][2];
			placeTrans = 0;

			for(int u = 0 ; u < tabDesc[i].nbTransExt*2 ; u++){
				if(u%2 == 0){
					transExt[placeTrans][0] = Lecture.lireInt(f2);
					System.out.print(transExt[placeTrans][0] + " ");
				}
				else{
					transExt[placeTrans][1] = Lecture.lireInt(f2);
					System.out.println(transExt[placeTrans][1]);
					placeTrans++;
				}
			}

			for(int q = 1 ; q <= tabDesc[i].tailleCode ; q++){
				po[transCode[i] + q] = Lecture.lireInt(f2);
				ipo++;
			}

			for(int h = 0; h < tabDesc[i].nbTransExt; h++){
				switch(transExt[h][1]){
				case 1 :
					po[transExt[h][0] + transCode[i]] += transDon[i];
					break;
				case 2 : 
					po[transExt[h][0] + transCode[i]] += transCode[i];
					break;
				case 3 :
					po[transExt[h][0] + transCode[i]] = adFinale[i][po[transExt[h][0] + transCode[i]]-1];
					break;
				default : break;
				}
				
			}
			Lecture.fermer(f2);
		}
		System.out.println("Début");
		for(int p = 1 ; p < tailleCode ; p++){
			System.out.println(po[p]);
		}
		
		for (int i=1;i<=ipo;i++) 
			Ecriture.ecrireStringln(f1,""+po[i]);
		Ecriture.fermer(f1);
		Mnemo.creerFichier(ipo,po,nomProg+".ima");
	}


	/**
	 * 
	 * @param nomDef
	 * 
	 * @return la présence d'une déf dans le dico
	 * 
	 */

	public static boolean presentDico(String nomDef){
		for(int i = 0 ; i < placeDico ; i++){
			if(dicoDef[0][i].equals(nomDef)){
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 * @param nomDef
	 * @return l'adresse de la procédure demandée
	 */
	public static int getDicoAdPo(String nomDef){
		for(int i = 0 ; i < placeDico ; i++){
			if(dicoDef[0][i].equals(nomDef))
				return Integer.parseInt(dicoDef[1][i]);
		}
		return -1;
	}

	public static void main (String argv[]) {
		System.out.println("EDITEUR DE LIENS / PROJET LICENCE");
		System.out.println("---------------------------------");
		System.out.println("");
		nbErr=0;
		//
		// Phase 1 de l"edition de liens
		//
		lireDescripteurs();	// lecture des descripteurs a completer eventuellement
		for(int i = 0 ; i <= nMod ; i++){
			System.out.println("i : " + i);
			Descripteur desc = tabDesc[i];
			System.out.println(desc);
			transDon[i] = tailleGlobaux;
			tailleGlobaux += desc.tailleGlobaux;

			transCode[i] = tailleCode;
			tailleCode += desc.tailleCode;

			for(int u = 1 ; u <= desc.nbDef ; u++){
				if(presentDico(desc.tabDef[u].nomProc))
					erreur(1, "Double définition d'une procédure");
				else{
					dicoDef[0][placeDico] = desc.tabDef[u].nomProc;
					dicoDef[1][placeDico] = "" + (desc.tabDef[u].adPo + transCode[i]);
					dicoDef[2][placeDico] = desc.tabDef[u].nbParam + "";
					placeDico++;
				}
			}
		}

		int adpo;
		for(int i = 0 ; i <= nMod ; i++){
			Descripteur desc = tabDesc[i];
			if(desc != null){
				for(int u = 1 ; u <= desc.nbRef ; u++){
					adpo = getDicoAdPo(desc.tabRef[u].nomProc);
					if(adpo != -1)
						adFinale[i][u-1] = adpo;
					else
						erreur(1, "Ref non trouvée dans le dico");
				}
				i++;
			}
		}
		/* 
		for(int tr : transDon){
			System.out.println(tr);
		}
		for(int tr : transCode){
			System.out.println(tr);
		}
		for(int u = 0 ; u < 6 ; u++){
			System.out.println(dicoDef[0][u] + " " + dicoDef[1][u] + " " + dicoDef[2][u]);
		}
		for(int u = 0 ; u < adFinale.length ; u++){
			System.out.println(adFinale[u][0] + " " + adFinale[u][1] + " " + adFinale[u][2] + " " + adFinale[u][3] + " " + adFinale[u][4] + " " + adFinale[u][5] + " "  + adFinale[u][6] + " "
					+ adFinale[u][7] + " "  + adFinale[u][8] + " " );
		}
		 */
		if (nbErr>0) {
			System.out.println("programme executable non produit");
			System.exit(1);
		}
		//
		// Phase 2 de l"edition de liens
		//
		constMap();	
		System.out.println("edition de liens terminee");
	}
}

